/*-------------------------------------------------------------------------
 *
 * 前端代码的查询结果打印支持
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/fe_utils/print.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef PRINT_H
#define PRINT_H

#include <signal.h>

#include "libpq-fe.h"


/* 这不是一个特别好的地方... */
#ifndef __CYGWIN__
#define DEFAULT_PAGER "more"
#else
#define DEFAULT_PAGER "less"
#endif

enum printFormat
{
	PRINT_NOTHING = 0,			/* 确保有人来初始化这个 */
	PRINT_ALIGNED,
	PRINT_ASCIIDOC,
	PRINT_CSV,
	PRINT_HTML,
	PRINT_LATEX,
	PRINT_LATEX_LONGTABLE,
	PRINT_TROFF_MS,
	PRINT_UNALIGNED,
	PRINT_WRAPPED
	/* 在这里添加你喜欢的输出格式... */
};

typedef struct printTextLineFormat
{
	/* 用于各种上下文的线条绘制字符 */
	const char *hrule;			/* 水平线字符 */
	const char *leftvrule;		/* 左垂直线（+水平） */
	const char *midvrule;		/* 列内垂直线（+水平） */
	const char *rightvrule;		/* 右垂直线（+水平） */
} printTextLineFormat;

typedef enum printTextRule
{
	/* 选择线条绘制字符的附加上下文 */
	PRINT_RULE_TOP,				/* 顶部水平线 */
	PRINT_RULE_MIDDLE,			/* 数据内水平线 */
	PRINT_RULE_BOTTOM,			/* 底部水平线 */
	PRINT_RULE_DATA				/* 数据线（此处不使用hrule） */
} printTextRule;

typedef enum printTextLineWrap
{
	/* 换行条件 */
	PRINT_LINE_WRAP_NONE,		/* 不换行 */
	PRINT_LINE_WRAP_WRAP,		/* 由于超长行而换行 */
	PRINT_LINE_WRAP_NEWLINE		/* 数据中的换行 */
} printTextLineWrap;

typedef struct printTextFormat
{
	/* 完整行样式 */
	const char *name;			/* 用于显示目的 */
	printTextLineFormat lrule[4];	/* 按枚举 printTextRule 索引 */
	const char *midvrule_nl;	/* 在换行后继续的垂直线 */
	const char *midvrule_wrap;	/* 用于换行数据的垂直线 */
	const char *midvrule_blank; /* 用于空白数据的垂直线 */
	const char *header_nl_left; /* 在换行后左侧标记 */
	const char *header_nl_right;	/* 换行的右侧标记 */
	const char *nl_left;		/* 在换行后左侧标记 */
	const char *nl_right;		/* 换行的右侧标记 */
	const char *wrap_left;		/* 在换行数据后左侧标记 */
	const char *wrap_right;		/* 在换行数据后的右侧标记 */
	bool		wrap_right_border;	/* 当 border=0 时使用右侧边框作为换行标记？ */
} printTextFormat;

typedef enum unicode_linestyle
{
	UNICODE_LINESTYLE_SINGLE = 0,
	UNICODE_LINESTYLE_DOUBLE
} unicode_linestyle;

struct separator
{
	char	   *separator;
	bool		separator_zero;
};

typedef struct printTableOpt
{
	enum printFormat format;	/* 参见上面的枚举 */
	unsigned short int expanded;	/* 扩展/垂直输出（如果输出格式支持）
									 * 0=否，1=是，2=自动 */
	unsigned short int border;	/* 在表格周围打印边框。 0=无，
								 * 1=分隔线，2=完整 */
	unsigned short int pager;	/* 使用分页器输出（如果输出到 stdout 且
								 * stdout 是一个 tty）0=关闭 1=开启 2=始终 */
	int			pager_min_lines;	/* 除非至少有这么多行，否则不使用分页器 */
	bool		tuples_only;	/* 不输出标题、行数等 */
	bool		start_table;	/* 打印开始装饰，例如 <table> */
	bool		stop_table;		/* 打印结束装饰，例如 </table> */
	bool		default_footer; /* 允许“（xx 行）”默认页脚 */
	unsigned long prior_records;	/* 记录计数器的起始偏移量 */
	const printTextFormat *line_style;	/* 行样式（NULL 为默认） */
	struct separator fieldSep;	/* 非对齐文本模式的字段分隔符 */
	struct separator recordSep; /* 非对齐文本模式的记录分隔符 */
	char		csvFieldSep[2]; /* csv 格式的字段分隔符 */
	bool		numericLocale;	/* 语言环境感知的数字单位分隔符和
								 * 小数标记 */
	char	   *tableAttr;		/* HTML <table ...>的属性 */
	int			encoding;		/* 字符编码 */
	int			env_columns;	/* psql 启动时的 $COLUMNS，0 为未设置 */
	int			columns;		/* 包装格式的目标宽度 */
	unicode_linestyle unicode_border_linestyle;
	unicode_linestyle unicode_column_linestyle;
	unicode_linestyle unicode_header_linestyle;
} printTableOpt;

/*
 * 表格底部被实现为一个单向链表。
 *
 * 这样您就不需要知道底部的数量就可以初始化
 * printTableContent 结构，这在准备复杂的底部时非常方便
 * （如 describeOneTableDetails 中所示）。
 */
typedef struct printTableFooter
{
	char	   *data;
	struct printTableFooter *next;
} printTableFooter;

/*
 * 表格内容结构保存printTable()将显示的所有信息。
 */
typedef struct printTableContent
{
	const printTableOpt *opt;
	const char *title;			/* 可能为 NULL */
	int			ncolumns;		/* 在 Init() 中指定 */
	int			nrows;			/* 在 Init() 中指定 */
	const char **headers;		/* 以 NULL 结束的头字符串数组 */
	const char **header;		/* 指向最后添加的头部的指针 */
	const char **cells;			/* 以 NULL 结束的单元内容字符串数组
								 * */
	const char **cell;			/* 指向最后添加的单元的指针 */
	long		cellsadded;		/* 到目前为止添加的单元数量 */
	bool	   *cellmustfree;	/* 需要进行 free() 的单元为 true */
	printTableFooter *footers;	/* 指向第一个底部的指针 */
	printTableFooter *footer;	/* 指向最后添加的底部的指针 */
	char	   *aligns;			/* 对齐说明符数组；'l'或'r'，
								 * 每列一个 */
	char	   *align;			/* 指向最后添加的对齐的指针 */
} printTableContent;

typedef struct printQueryOpt
{
	printTableOpt topt;			/* 以上选项 */
	char	   *nullPrint;		/* 如何打印空实体 */
	char	   *title;			/* 覆盖标题 */
	char	  **footers;		/* 覆盖底部（默认是“（xx行）”） */
	bool		translate_header;	/* 对列头进行 gettext */
	const bool *translate_columns;	/* translate_columns[i-1] => 对列 i 进行 gettext */
	int			n_translate_columns;	/* translate_columns[] 的长度 */
} printQueryOpt;


extern PGDLLIMPORT volatile sig_atomic_t cancel_pressed;

extern PGDLLIMPORT const printTextFormat pg_asciiformat;
extern PGDLLIMPORT const printTextFormat pg_asciiformat_old;
extern PGDLLIMPORT printTextFormat pg_utf8format;	/* 理想情况下应该是 const，
													 * 但是… */


extern void disable_sigpipe_trap(void);
extern void restore_sigpipe_trap(void);
extern void set_sigpipe_trap_state(bool ignore);

extern FILE *PageOutput(int lines, const printTableOpt *topt);
extern void ClosePager(FILE *pagerpipe);

extern void html_escaped_print(const char *in, FILE *fout);

extern void printTableInit(printTableContent *const content,
						   const printTableOpt *opt, const char *title,
						   const int ncolumns, const int nrows);
extern void printTableAddHeader(printTableContent *const content,
								char *header, const bool translate, const char align);
extern void printTableAddCell(printTableContent *const content,
							  char *cell, const bool translate, const bool mustfree);
extern void printTableAddFooter(printTableContent *const content,
								const char *footer);
extern void printTableSetFooter(printTableContent *const content,
								const char *footer);
extern void printTableCleanup(printTableContent *const content);
extern void printTable(const printTableContent *cont,
					   FILE *fout, bool is_pager, FILE *flog);
extern void printQuery(const PGresult *result, const printQueryOpt *opt,
					   FILE *fout, bool is_pager, FILE *flog);

extern char column_type_alignment(Oid);

extern void setDecimalLocale(void);
extern const printTextFormat *get_line_style(const printTableOpt *opt);
extern void refresh_utf8format(const printTableOpt *opt);

#endif							/* PRINT_H */
